package com.roy.jsound;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.TargetDataLine;

public class RecordPlay {

	private boolean stopCapture = false;	//控制录音标志位
	AudioFormat audioFormat;	//录音格式
	
	//读取数据，从TargetDataLine 写入 ByteArrayOutputStream录音
	ByteArrayOutputStream byteArrayOutPutStream;
	int totalDataSize = 0;
	TargetDataLine targetDataLine;
	
	//播放数据: 从audioInputStream写入sourceDataLine
	AudioInputStream audioInputStream;
	SourceDataLine sourceDataLine;
	
	private AudioFormat getAudioFormat(){
		float sampleRate = 16000.0F; //8000, 11025, 16000 22050, 44100
		int sampleSizeInBits = 16; //8, 16
		int channel = 1; //1, 2
		boolean signed = true;
		boolean bigEndian = false;
		return new AudioFormat(sampleRate, sampleSizeInBits, channel, signed, bigEndian);
	}
	
	/**
	 * 录音
	 */
	public void capture(){
		try {
			audioFormat = getAudioFormat();
			DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);
			targetDataLine = (TargetDataLine)AudioSystem.getLine(dataLineInfo);
			
			targetDataLine.open(audioFormat);
			targetDataLine.start();
			
			Thread captureThread = new CaptureThread();
			captureThread.start();
		} catch (LineUnavailableException e) {
			e.printStackTrace();
			System.exit(0);
		}
	}
	
	public void play(){
		try {
			byte[] audioData = byteArrayOutPutStream.toByteArray();
			InputStream byteArrayInputStream = new ByteArrayInputStream(audioData);
			AudioFormat audioFormat = getAudioFormat();
			
			audioInputStream = new AudioInputStream(byteArrayInputStream , 
													audioFormat, 
													audioData.length / audioFormat.getFrameSize());
			
			DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, audioFormat);
			sourceDataLine = (SourceDataLine)AudioSystem.getLine(dataLineInfo);
			sourceDataLine.open(audioFormat);
			sourceDataLine.start();
			
			Thread playThread = new PlayThread();
			playThread.start();
		} catch (LineUnavailableException e) {
			e.printStackTrace();
		}
	}
	
	public void stop(){
		stopCapture = true;
	}
	
	public void save(){
		AudioFormat audioFormat = getAudioFormat();
		byte[] audioData = byteArrayOutPutStream.toByteArray();
		InputStream byteArrayInputStream = new ByteArrayInputStream(audioData);
		audioInputStream = new AudioInputStream(byteArrayInputStream , 
				audioFormat, 
				audioData.length / audioFormat.getFrameSize());
		
		try {
			File f = new File("D://test.wav");
			AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, f);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	/**
	 * 录音线程
	 * @author rzpeng
	 *
	 */
	class CaptureThread extends Thread {

		byte[] tempBuffer = new byte[10000];
		
		public void run(){
			byteArrayOutPutStream = new ByteArrayOutputStream();
			totalDataSize = 0;
			stopCapture = false;
			
			try {
				while(stopCapture){
					int cnt = targetDataLine.read(tempBuffer, 0, tempBuffer.length);
					if(cnt > 0){
						byteArrayOutPutStream.write(tempBuffer, 0, cnt);
					}
					
				}
				byteArrayOutPutStream.close();
			} catch (IOException e) {
				e.printStackTrace();
				System.exit(0);
			}
			
		}
		
	}
	
	/**
	 * 播放线程
	 * @author rzpeng
	 *
	 */
	class PlayThread extends Thread {

		byte[] tempBuffer = new byte[10000];
		
		public void run(){
			byteArrayOutPutStream = new ByteArrayOutputStream();
			totalDataSize = 0;
			stopCapture = false;
			
			try {
				int cnt;
				while((cnt = audioInputStream.read(tempBuffer, 0, tempBuffer.length)) != -1){
					if(cnt > 0){
						sourceDataLine.write(tempBuffer, 0, cnt);
					}
				}
				//Block 等待临时数据被清空
				sourceDataLine.drain();
				sourceDataLine.close();
			} catch (IOException e) {
				e.printStackTrace();
				System.exit(0);
			}
			
		}
		
	}
	
	
}
